﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using GpgApi;
using Microsoft.Win32;
using WgpgCore;

namespace WgpgGUI
{
    public partial class EncryptionDialog : Window, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private ListCollectionView _publicCollectionView = null;
        private ListCollectionView _secretCollectionView = null;
        private String _originalFileName = null;
        private String _encryptedFileName = null;
        private Boolean _asciiArmored = true;
        private Boolean _hideUserId = false;
        private Boolean _usePublicKey = true;
        private Boolean _useCipherAlgorithm = false;
        private Boolean _signFile = false;
        private Boolean _encryptToFile = true;
        private Boolean _showExtraOptions = false;

        public EncryptionDialog() : this(null)
        {
        }

        public EncryptionDialog(Window owner)
        {
            Owner = owner;
            InitializeComponent();

            _publicCollectionView = new ListCollectionView(KeyManager.Keys)
            {
                Filter = FilterPublic,
                CustomSort = new KeyNodeSort(false)
            };

            _secretCollectionView = new ListCollectionView(KeyManager.Keys)
            {
                Filter = FilterSecret,
                CustomSort = new KeyNodeSort(false)
            };

            listPublic.DataContext = _publicCollectionView;
            cboBoxSignature.DataContext = _secretCollectionView;

            DataContext = this;
        }

        public Boolean EncryptToFile
        {
            get { return _encryptToFile; }
            set
            {
                if (value != _encryptToFile)
                {
                    _encryptToFile = value;
                    NotifyPropertyChanged("EncryptToFile");
                }
            }
        }

        public String OriginalFileName
        {
            get { return _originalFileName; }
            set
            {
                if (value != _originalFileName)
                {
                    _originalFileName = value;
                    NotifyPropertyChanged("OriginalFilename");
                }
            }
        }

        public String EncryptedFileName
        {
            get { return _encryptedFileName; }
            set
            {
                if (value != _encryptedFileName)
                {
                    _encryptedFileName = value;
                    NotifyPropertyChanged("EncryptedFilename");
                }
            }
        }

        public Boolean UsePublicKey
        {
            get { return _usePublicKey; }
            set
            {
                if (value != _usePublicKey)
                {
                    _usePublicKey = value;
                    NotifyPropertyChanged("UsePublicKey");
                }
            }
        }

        // TODO, permettre de spécifier une liste de KeyId sélectionnés.
        public List<KeyId> PublicRecipients
        {
            get
            {
                IList l = listPublic.SelectedItems;
                if (l == null || l.Count == 0)
                    return null;

                List<KeyId> list = new List<KeyId>();
                foreach (Object item in l)
                {
                    KeyNode node = item as KeyNode;
                    list.Add(node.Id);
                }

                return list;
            }
        }

        public Boolean UseCipherAlgorithm
        {
            get { return _useCipherAlgorithm; }
            set
            {
                if (value != _useCipherAlgorithm)
                {
                    _useCipherAlgorithm = value;
                    NotifyPropertyChanged("UseCipherAlgorithm");
                }
            }
        }

        public CipherAlgorithm CipherAlgorithm
        {
            get
            {
                ComboBoxItem item = cboBoxCipher.SelectedItem as ComboBoxItem;
                return item == null ? CipherAlgorithm.None : (CipherAlgorithm)item.Tag;
            }

            set
            {
                if (cboBoxCipher == null || cboBoxCipher.Items == null)
                    return;

                // TODO faire une sorte de binding pour que la combobox se mette à jour toute seule et soit basée sur le NotifyPropertyChanged.
                foreach (Object obj in cboBoxCipher.Items)
                {
                    ComboBoxItem item = obj as ComboBoxItem;
                    CipherAlgorithm tag = (CipherAlgorithm)item.Tag;
                    item.IsSelected = tag == value;
                }

                NotifyPropertyChanged("CipherAlgorithm");
            }
        }

        public Boolean SignFile
        {
            get { return _signFile; }
            set
            {
                if (value != _signFile)
                {
                    _signFile = value;
                    NotifyPropertyChanged("SignFile");
                }
            }
        }

        public KeyId SignatureKeyId
        {
            get
            {
                KeyNode node = cboBoxSignature.SelectedItem as KeyNode;
                return node == null ? null : node.Id;
            }

            set
            {
                if (_secretCollectionView == null)
                    return;

                // TODO faire une sorte de binding pour que la combobox se mette à jour toute seule et soit basée sur le NotifyPropertyChanged.
                Int32 count = _secretCollectionView.Count;
                for (Int32 i = 0; i < count; ++i)
                {
                    KeyNode node = _secretCollectionView.GetItemAt(i) as KeyNode;
                    ComboBoxItem item = (ComboBoxItem)cboBoxSignature.ItemContainerGenerator.ContainerFromItem(i);
                    item.IsSelected = node.Id == value;
                }

                NotifyPropertyChanged("SignatureKeyId");
            }
        }

        public Boolean ShowExtraOptions
        {
            get { return _showExtraOptions; }
            set
            {
                if (value != _showExtraOptions)
                {
                    _showExtraOptions = value;
                    NotifyPropertyChanged("ShowExtraOptions");
                }
            }
        }

        public Boolean ASCIIArmored
        {
            get { return _asciiArmored; }
            set
            {
                if (value != _asciiArmored)
                {
                    _asciiArmored = value;
                    NotifyPropertyChanged("ASCIIArmored");
                }
            }
        }

        public Boolean HideUserId
        {
            get { return _hideUserId; }
            set
            {
                if (value != _hideUserId)
                {
                    _hideUserId = value;
                    NotifyPropertyChanged("HideUserId");
                }
            }
        }

        public static RoutedCommand EncryptCommand = new RoutedCommand();

        private void Encrypt_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = false;

            if (String.IsNullOrEmpty(EncryptedFileName) || !Utils.IsValidPath(EncryptedFileName))
                return;

            if (!UsePublicKey && !UseCipherAlgorithm)
                return;

            if (UsePublicKey && PublicRecipients == null)
                return;
            
            e.CanExecute = true;
        }

        private void Encrypt_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;
            DialogResult = true;
            Close();
        }

        private void CancelClick(Object sender, RoutedEventArgs e)
        {
            DialogResult = false;
            Close();
        }

        private void SelectFileName(Object sender, RoutedEventArgs e)
        {
            SaveFileDialog saveDialog = new SaveFileDialog
            {
                Title = L10N.T("save_encrypted_file"),
                CheckFileExists = false,
                CheckPathExists = true,
                Filter = L10N.T("filter_wgpgfiles") + "|*.wgpg",
                FileName = EncryptedFileName
            };

            if (saveDialog.ShowDialog(this) != true)
                return;

            EncryptedFileName = saveDialog.FileName;
        }

        private void NotifyPropertyChanged(String name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }

        private static Boolean FilterSecret(Object item)
        {
            KeyNodeFilter filter = new KeyNodeFilter
            {
                PublicKeys = false,
                SecretKeys = true
            };

            return filter.Match(item as KeyNode);
        }

        private static Boolean FilterPublic(Object item)
        {
            KeyNodeFilter filter = new KeyNodeFilter
            {
                PublicKeys = true,
                SecretKeys = true
            };

            return filter.Match(item as KeyNode);
        }
    }
}
